<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>18.2.1-将虚拟 DOM 渲染为 HTML 字符串</title>
</head>
<body>
    
</body>
    <script>
        /**
         * 如何在服务端将虚拟 DOM 渲染为 HTML 字符串
         * 
         * renderElementVNode 函数的实现仅仅用来展示将虚拟DOM 渲染为 HTML 字符串的核心原理，
         *  并不满足生产要求，因为它存在以下几点缺陷。
         * - renderElementVNode 函数在渲染标签类型的虚拟节点时，还需要考虑该节点是否是自闭合标签
         * - 对于属性（props）的处理会比较复杂，要考虑属性名称是否合法，还要对属性值进行 HTML 转义。
         * - 子节点的类型多种多样，可能是任意类型的虚拟节点，
         *     如 Fragment、组件、函数式组件、文本等，这些都需要处理
         * - 标签的文本子节点也需要进行 HTML 转义
        */
       
        // 给出如下虚拟节点对象
        const ElementVNode = { // 新增 ElementVNode 对象
            type: 'div',
            props: {
                id: 'foo'
            },
            children: [
                { type: 'p', children: 'hello' }
            ]
        }

        // 在不考虑任何边界条件的情况下，实现 renderElementVNode
        function renderElementVNode(vnode){ // 新增 renderElementVNode 函数
            // 取出标签名称 tag 和标签属性 props，以及标签的子节点
            const { type: tag, props, children } = vnode
            // 开始标签的头部
            let ret = `<${tag}`
            // 处理标签属性
            if (props) {
                for (const k in props) {
                    // 以 key="value" 的形式拼接字符串
                    ret += ` ${k}="${props[k]}"`
                }
            }
            // 开始标签的闭合
            ret += `>`

            // 处理子节点
            // 如果子节点的类型是字符串，则是文本内容，直接拼接
            if (typeof children === 'string') {
                ret += children
            } else if (Array.isArray(children)) {
                // 如果子节点的类型是数组，则递归地调用 renderElementVNode 完成渲染
                children.forEach(child => {
                    ret += renderElementVNode(child)
                })
            }

            // 结束标签
            ret += `</${tag}>`

            // 返回拼接好的 HTML 字符串
            return ret
        }

        // 测试
        console.log(renderElementVNode(ElementVNode))
    </script>
</html>